<!DOCTYPE html>
<html lang="en">
<head>
    
    <meta charset="utf-8">
    <title>my-three-menu/src/ThreeMenu.vue - Documentation</title>
    
    
    <script src="scripts/prettify/prettify.js"></script>
    <script src="scripts/prettify/lang-css.js"></script>
    <link type="text/css" rel="stylesheet" href="styles/prettify.css">
    <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
    <script src="scripts/nav.js" defer></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>

<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x">
  <div class="navicon"></div>
</label>

<label for="nav-trigger" class="overlay"></label>

<nav >
    
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Outline.html">Outline</a></li><li><a href="Tag.html">Tag</a></li><li><a href="TagCanvas.html">TagCanvas</a></li></ul><h3>Modules</h3><ul><li><a href="module-$ui_components_my-affix.html">$ui/components/my-affix</a></li><li><a href="module-$ui_components_my-anchor.html">$ui/components/my-anchor</a></li><li><a href="module-$ui_components_my-at-input.html">$ui/components/my-at-input</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-at-input.html#~getData">getData</a></li><li data-type='method'><a href="module-$ui_components_my-at-input.html#~setData">setData</a></li><li data-type='method'><a href="module-$ui_components_my-at-input.html#~tagInsert">tagInsert</a></li><li data-type='method'><a href="module-$ui_components_my-at-input.html#~togglePopover">togglePopover</a></li></ul></li><li><a href="module-$ui_components_my-autocomplete.html">$ui/components/my-autocomplete</a></li><li><a href="module-$ui_components_my-avatar.html">$ui/components/my-avatar</a></li><li><a href="module-$ui_components_my-avatars.html">$ui/components/my-avatars</a></li><li><a href="module-$ui_components_my-back-top.html">$ui/components/my-back-top</a></li><li><a href="module-$ui_components_my-breadcrumb.html">$ui/components/my-breadcrumb</a></li><li><a href="module-$ui_components_my-capture.html">$ui/components/my-capture</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-capture.html#~_renderImg">_renderImg</a></li></ul></li><li><a href="module-$ui_components_my-card-list.html">$ui/components/my-card-list</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-card-list.html#~refresh">refresh</a></li></ul></li><li><a href="module-$ui_components_my-cascader.html">$ui/components/my-cascader</a></li><li><a href="module-$ui_components_my-checkbox.html">$ui/components/my-checkbox</a></li><li><a href="module-$ui_components_my-clipboard.html">$ui/components/my-clipboard</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-clipboard.html#~copy">copy</a></li></ul></li><li><a href="module-$ui_components_my-color-picker.html">$ui/components/my-color-picker</a></li><li><a href="module-$ui_components_my-contextmenu.html">$ui/components/my-contextmenu</a></li><li><a href="module-$ui_components_my-corner-mark.html">$ui/components/my-corner-mark</a></li><li><a href="module-$ui_components_my-crud.html">$ui/components/my-crud</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-crud.html#~openAddDialog">openAddDialog</a></li><li data-type='method'><a href="module-$ui_components_my-crud.html#~refresh">refresh</a></li><li data-type='method'><a href="module-$ui_components_my-crud.html#~reload">reload</a></li></ul></li><li><a href="module-$ui_components_my-date.html">$ui/components/my-date</a></li><li><a href="module-$ui_components_my-date-picker.html">$ui/components/my-date-picker</a></li><li><a href="module-$ui_components_my-description.html">$ui/components/my-description</a></li><li><a href="module-$ui_components_my-detail.html">$ui/components/my-detail</a></li><li><a href="module-$ui_components_my-detail-item.html">$ui/components/my-detail-item</a></li><li><a href="module-$ui_components_my-dialog.html">$ui/components/my-dialog</a></li><li><a href="module-$ui_components_my-drag.html">$ui/components/my-drag</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-drag.html#~getRelativeEl">getRelativeEl</a></li></ul></li><li><a href="module-$ui_components_my-drop.html">$ui/components/my-drop</a></li><li><a href="module-$ui_components_my-edit-tags.html">$ui/components/my-edit-tags</a></li><li><a href="module-$ui_components_my-editor.html">$ui/components/my-editor</a></li><li><a href="module-$ui_components_my-empty.html">$ui/components/my-empty</a></li><li><a href="module-$ui_components_my-filter.html">$ui/components/my-filter</a></li><li><a href="module-$ui_components_my-fixed.html">$ui/components/my-fixed</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-fixed.html#~resize">resize</a></li></ul></li><li><a href="module-$ui_components_my-flex.html">$ui/components/my-flex</a></li><li><a href="module-$ui_components_my-flex-item.html">$ui/components/my-flex-item</a></li><li><a href="module-$ui_components_my-flip.html">$ui/components/my-flip</a></li><li><a href="module-$ui_components_my-float.html">$ui/components/my-float</a></li><li><a href="module-$ui_components_my-float-item.html">$ui/components/my-float-item</a></li><li><a href="module-$ui_components_my-form.html">$ui/components/my-form</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-form.html#~reset">reset</a></li><li data-type='method'><a href="module-$ui_components_my-form.html#~submit">submit</a></li></ul></li><li><a href="module-$ui_components_my-form_src_Base.html">$ui/components/my-form/src/Base</a></li><li><a href="module-$ui_components_my-form_src_common_TagInput.html">$ui/components/my-form/src/common/TagInput</a></li><li><a href="module-$ui_components_my-form_src_common_TagSelect.html">$ui/components/my-form/src/common/TagSelect</a></li><li><a href="module-$ui_components_my-form_src_common_TreeSelect.html">$ui/components/my-form/src/common/TreeSelect</a></li><li><a href="module-$ui_components_my-header.html">$ui/components/my-header</a></li><li><a href="module-$ui_components_my-highlight.html">$ui/components/my-highlight</a></li><li><a href="module-$ui_components_my-icon.html">$ui/components/my-icon</a></li><li><a href="module-$ui_components_my-im-wall.html">$ui/components/my-im-wall</a></li><li><a href="module-$ui_components_my-input.html">$ui/components/my-input</a></li><li><a href="module-$ui_components_my-input-number.html">$ui/components/my-input-number</a></li><li><a href="module-$ui_components_my-key-val-list.html">$ui/components/my-key-val-list</a></li><li><a href="module-$ui_components_my-layout.html">$ui/components/my-layout</a></li><li><a href="module-$ui_components_my-lazy.html">$ui/components/my-lazy</a></li><li><a href="module-$ui_components_my-list.html">$ui/components/my-list</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-list.html#~load">load</a></li><li data-type='method'><a href="module-$ui_components_my-list.html#~refresh">refresh</a></li><li data-type='method'><a href="module-$ui_components_my-list.html#~reset">reset</a></li><li data-type='method'><a href="module-$ui_components_my-list.html#~scrollTop">scrollTop</a></li></ul></li><li><a href="module-$ui_components_my-location-picker.html">$ui/components/my-location-picker</a></li><li><a href="module-$ui_components_my-login.html">$ui/components/my-login</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-login.html#~submit">submit</a></li></ul></li><li><a href="module-$ui_components_my-marquee.html">$ui/components/my-marquee</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-marquee.html#~pause">pause</a></li><li data-type='method'><a href="module-$ui_components_my-marquee.html#~start">start</a></li><li data-type='method'><a href="module-$ui_components_my-marquee.html#~stop">stop</a></li></ul></li><li><a href="module-$ui_components_my-master-app.html">$ui/components/my-master-app</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-master-app.html#~initState">initState</a></li><li data-type='method'><a href="module-$ui_components_my-master-app.html#~onStateChange">onStateChange</a></li><li data-type='method'><a href="module-$ui_components_my-master-app.html#~onStateChange">onStateChange</a></li><li data-type='method'><a href="module-$ui_components_my-master-app.html#~setState">setState</a></li></ul></li><li><a href="module-$ui_components_my-menu.html">$ui/components/my-menu</a></li><li><a href="module-$ui_components_my-micro-app.html">$ui/components/my-micro-app</a></li><li><a href="module-$ui_components_my-navbar.html">$ui/components/my-navbar</a></li><li><a href="module-$ui_components_my-navbar-FullScreenAction.html">$ui/components/my-navbar-FullScreenAction</a></li><li><a href="module-$ui_components_my-navbar-IconAction.html">$ui/components/my-navbar-IconAction</a></li><li><a href="module-$ui_components_my-navbar-UserAction.html">$ui/components/my-navbar-UserAction</a></li><li><a href="module-$ui_components_my-number.html">$ui/components/my-number</a></li><li><a href="module-$ui_components_my-panel.html">$ui/components/my-panel</a></li><li><a href="module-$ui_components_my-paragraph.html">$ui/components/my-paragraph</a></li><li><a href="module-$ui_components_my-particle.html">$ui/components/my-particle</a></li><li><a href="module-$ui_components_my-popper.html">$ui/components/my-popper</a></li><li><a href="module-$ui_components_my-pro.html">$ui/components/my-pro</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-pro.html#~addTab">addTab</a></li><li data-type='method'><a href="module-$ui_components_my-pro.html#~closeTabs">closeTabs</a></li><li data-type='method'><a href="module-$ui_components_my-pro.html#~setTab">setTab</a></li></ul></li><li><a href="module-$ui_components_my-promise.html">$ui/components/my-promise</a></li><li><a href="module-$ui_components_my-radial-menu.html">$ui/components/my-radial-menu</a></li><li><a href="module-$ui_components_my-radio.html">$ui/components/my-radio</a></li><li><a href="module-$ui_components_my-range.html">$ui/components/my-range</a></li><li><a href="module-$ui_components_my-rate.html">$ui/components/my-rate</a></li><li><a href="module-$ui_components_my-resize.html">$ui/components/my-resize</a></li><li><a href="module-$ui_components_my-result.html">$ui/components/my-result</a></li><li><a href="module-$ui_components_my-revolve.html">$ui/components/my-revolve</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-revolve.html#~next">next</a></li><li data-type='method'><a href="module-$ui_components_my-revolve.html#~prev">prev</a></li><li data-type='method'><a href="module-$ui_components_my-revolve.html#~start">start</a></li><li data-type='method'><a href="module-$ui_components_my-revolve.html#~stop">stop</a></li></ul></li><li><a href="module-$ui_components_my-search-box.html">$ui/components/my-search-box</a></li><li><a href="module-$ui_components_my-select.html">$ui/components/my-select</a></li><li><a href="module-$ui_components_my-sidebar.html">$ui/components/my-sidebar</a></li><li><a href="module-$ui_components_my-skeleton.html">$ui/components/my-skeleton</a></li><li><a href="module-$ui_components_my-slide-layout.html">$ui/components/my-slide-layout</a></li><li><a href="module-$ui_components_my-slider.html">$ui/components/my-slider</a></li><li><a href="module-$ui_components_my-sortable.html">$ui/components/my-sortable</a></li><li><a href="module-$ui_components_my-spin.html">$ui/components/my-spin</a></li><li><a href="module-$ui_components_my-stat-card.html">$ui/components/my-stat-card</a></li><li><a href="module-$ui_components_my-svg-line.html">$ui/components/my-svg-line</a></li><li><a href="module-$ui_components_my-switch.html">$ui/components/my-switch</a></li><li><a href="module-$ui_components_my-table.html">$ui/components/my-table</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-table.html#~refresh">refresh</a></li></ul></li><li><a href="module-$ui_components_my-tabs.html">$ui/components/my-tabs</a></li><li><a href="module-$ui_components_my-tag-canvas.html">$ui/components/my-tag-canvas</a></li><li><a href="module-$ui_components_my-tag-input.html">$ui/components/my-tag-input</a></li><li><a href="module-$ui_components_my-tag-select.html">$ui/components/my-tag-select</a></li><li><a href="module-$ui_components_my-text.html">$ui/components/my-text</a></li><li><a href="module-$ui_components_my-three-menu.html">$ui/components/my-three-menu</a></li><li><a href="module-$ui_components_my-timer.html">$ui/components/my-timer</a><ul class='methods'><li data-type='method'><a href="module-$ui_components_my-timer.html#~reset">reset</a></li><li data-type='method'><a href="module-$ui_components_my-timer.html#~start">start</a></li><li data-type='method'><a href="module-$ui_components_my-timer.html#~stop">stop</a></li></ul></li><li><a href="module-$ui_components_my-title.html">$ui/components/my-title</a></li><li><a href="module-$ui_components_my-tree-select.html">$ui/components/my-tree-select</a></li><li><a href="module-$ui_components_my-typography.html">$ui/components/my-typography</a></li><li><a href="module-$ui_components_my-water-fall.html">$ui/components/my-water-fall</a></li><li><a href="module-$ui_components_my-watermark.html">$ui/components/my-watermark</a></li><li><a href="module-$ui_components_my-wave.html">$ui/components/my-wave</a></li><li><a href="module-$ui_components_my-wrapper.html">$ui/components/my-wrapper</a></li><li><a href="module-widgets_my-print.html">widgets/my-print</a></li></ul><h3>Events</h3><ul><li><a href="module-$ui_components_my-stat-card.html#~event:action">action</a></li><li></li><li><a href="module-$ui_components_my-form_src_common_TagInput.html#~event:add">add</a></li><li><a href="module-$ui_components_my-wrapper.html#~event:back">back</a></li><li><a href="module-$ui_components_my-dialog.html#~event:cancel">cancel</a></li><li><a href="module-$ui_components_my-typography.html#~event:change">change</a></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-tag-canvas.html#~event:click">click</a></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-avatars.html#~event:click-add">click-add</a></li><li><a href="module-$ui_components_my-avatars.html#~event:click-item">click-item</a></li><li><a href="module-$ui_components_my-avatars.html#~event:click-more">click-more</a></li><li><a href="module-$ui_components_my-radial-menu.html#~event:close">close</a></li><li></li><li><a href="module-$ui_components_my-pro.html#~event:collapse">collapse</a></li><li><a href="module-$ui_components_my-form_src_common_TagSelect.html#~event:collapsed">collapsed</a></li><li><a href="module-$ui_components_my-table.html#~event:column-change">column-change</a></li><li><a href="module-$ui_components_my-table.html#~event:column-change-confirm">column-change-confirm</a></li><li><a href="module-$ui_components_my-navbar-UserAction.html#~event:command">command</a></li><li></li><li></li><li><a href="global.html#event:complete">complete</a></li><li></li><li><a href="module-$ui_components_my-typography.html#event:copy">copy</a></li><li></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-drag.html#~event:drag">drag</a></li><li></li><li><a href="module-$ui_components_my-dialog.html#~event:drag-start">drag-start</a></li><li><a href="module-$ui_components_my-dialog.html#~event:drag-stop">drag-stop</a></li><li><a href="module-$ui_components_my-drop.html#~event:drop">drop</a></li><li><a href="module-$ui_components_my-typography.html#event:edited">edited</a></li><li></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-typography.html#event:editing">editing</a></li><li></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-drop.html#~event:enter">enter</a></li><li><a href="module-$ui_components_my-table.html#~event:error">error</a></li><li></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-typography.html#event:expand">expand</a></li><li></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-timer.html#~event:finish">finish</a></li><li><a href="module-$ui_components_my-dialog.html#~event:hide">hide</a></li><li><a href="module-$ui_components_my-lazy.html#~event:init">init</a></li><li><a href="module-$ui_components_my-form_src_common_TagInput.html#~event:input-change">input-change</a></li><li><a href="module-$ui_components_my-drop.html#~event:leave">leave</a></li><li><a href="module-$ui_components_my-wrapper.html#~event:link-click">link-click</a></li><li><a href="module-$ui_components_my-dialog.html#~event:load">load</a></li><li><a href="module-$ui_components_my-revolve.html#~event:loaded">loaded</a></li><li><a href="module-$ui_components_my-dialog.html#~event:maximize">maximize</a></li><li><a href="module-$ui_components_my-im-wall.html#~event:on-added">on-added</a></li><li><a href="module-$ui_components_my-capture.html#~event:on-capture">on-capture</a></li><li><a href="global.html#event:on-change">on-change</a></li><li><a href="module-$ui_components_my-capture.html#~event:on-output">on-output</a></li><li><a href="module-$ui_components_my-at-input.html#~event:on-popToggle">on-popToggle</a></li><li></li><li><a href="module-$ui_components_my-slide-layout.html#~event:on-ready">on-ready</a></li><li><a href="module-$ui_components_my-slide-layout.html#~event:on-resize">on-resize</a></li><li><a href="module-$ui_components_my-at-input.html#~event:on-tagEdit">on-tagEdit</a></li><li><a href="module-$ui_components_my-radial-menu.html#~event:open">open</a></li><li></li><li><a href="module-$ui_components_my-drop.html#~event:over">over</a></li><li><a href="global.html#~event:page-change">page-change</a></li><li></li><li></li><li><a href="module-$ui_components_my-login.html#~event:pki">pki</a></li><li><a href="module-$ui_components_my-revolve.html#~event:progress">progress</a></li><li><a href="module-$ui_components_my-form_src_common_TagInput.html#~event:remove">remove</a></li><li><a href="module-$ui_components_my-timer.html#~event:reset">reset</a></li><li></li><li><a href="module-$ui_components_my-resize.html#~event:resize">resize</a></li><li></li><li><a href="module-$ui_components_my-dialog.html#~event:resize-start">resize-start</a></li><li><a href="module-$ui_components_my-dialog.html#~event:resize-stop">resize-stop</a></li><li><a href="module-$ui_components_my-search-box.html#~event:search">search</a></li><li><a href="module-$ui_components_my-sidebar.html#~event:select">select</a></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-dialog.html#~event:show">show</a></li><li><a href="global.html#~event:size-change">size-change</a></li><li></li><li></li><li><a href="module-$ui_components_my-timer.html#~event:start">start</a></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-timer.html#~event:stop">stop</a></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-login.html#~event:submit">submit</a></li><li></li><li></li><li><a href="module-$ui_components_my-table.html#~event:success">success</a></li><li></li><li></li><li></li><li></li><li></li><li><a href="module-$ui_components_my-panel.html#~event:tab-change">tab-change</a></li><li><a href="module-$ui_components_my-pro.html#~event:tab-remove">tab-remove</a></li><li><a href="module-$ui_components_my-pro.html#~event:tab-select">tab-select</a></li><li><a href="module-$ui_components_my-timer.html#~event:tick">tick</a></li><li><a href="module-$ui_components_my-form.html#~event:validate">validate</a></li><li><a href="module-$ui_components_my-form.html#~event:validate-fail">validate-fail</a></li><li><a href="module-$ui_components_my-form.html#~event:validate-success">validate-success</a></li><li><a href="module-widgets_my-back-top.html#event:click">click</a></li></ul><h3>Global</h3><ul><li><a href="global.html#AddShadowToImage">AddShadowToImage</a></li><li><a href="global.html#appendChildNode">appendChildNode</a></li><li><a href="global.html#createEllipsisContainer">createEllipsisContainer</a></li><li><a href="global.html#createEllipsisContentHolder">createEllipsisContentHolder</a></li><li><a href="global.html#destroyVue">destroyVue</a></li><li><a href="global.html#getData">getData</a></li><li><a href="global.html#inRange">inRange</a></li><li><a href="global.html#instanceVue">instanceVue</a></li><li><a href="global.html#props">props</a></li><li><a href="global.html#pxToNumber">pxToNumber</a></li><li><a href="global.html#removeEllipsisContainer">removeEllipsisContainer</a></li><li><a href="global.html#RoundImage">RoundImage</a></li><li><a href="global.html#scrollTop">scrollTop</a></li><li><a href="global.html#setData">setData</a></li><li><a href="global.html#styleToString">styleToString</a></li><li><a href="global.html#wrapperDecorations">wrapperDecorations</a></li></ul>
</nav>

<div id="main">
    
    <h1 class="page-title">my-three-menu/src/ThreeMenu.vue</h1>
    

    



    
    <section>
        <article>
            <pre class="prettyprint source linenums"><code>&lt;template>
  &lt;div class="my-three-menu" :style="styles">
    &lt;div class="my-three-menu__container" ref="container">
      &lt;div
        v-for="(item, idx) in this.elements"
        :key="idx"
        class="my-three-menu__item"
        style="display: none"
        :data-index="idx"
      >
        &lt;slot name="item" :item="item">&lt;/slot>
      &lt;/div>
    &lt;/div>
    &lt;slot>&lt;/slot>
    &lt;div class="my-three-menu__menu">
      &lt;div class="table my-three-menu__button" ref="table" v-if="showTab" @click="transLayout('table')">
        &lt;MyIcon :name="'icon-all-fill'" svg>&lt;/MyIcon>
      &lt;/div>
      &lt;div class="sphere my-three-menu__button" ref="sphere" v-if="showTab"  @click="transLayout('sphere')">
        &lt;MyIcon :name="'icon-network'" svg>&lt;/MyIcon>
      &lt;/div>
      &lt;div class="helix my-three-menu__button" ref="helix" v-if="showTab"  @click="transLayout('helix')">
        &lt;MyIcon :name="'icon-odbc'" svg>&lt;/MyIcon>
      &lt;/div>
      &lt;div class="grid my-three-menu__button" ref="grid" v-if="showTab"  @click="transLayout('grid')">
        &lt;MyIcon :name="'icon-copy-rect-fill'" svg>&lt;/MyIcon>
      &lt;/div>
      &lt;div
      v-if="showTab &amp;&amp; currLayout === 'grid'"
        :class="['prev', 'my-three-menu__button', { disabled: gridIndex === 0 }]"
        ref="prev"
        @click="jumpPrev()"
      >
        &lt;MyIcon :name="'icon-mono-left-fill'" svg>&lt;/MyIcon>
      &lt;/div>
      &lt;div
      v-if="showTab &amp;&amp; currLayout === 'grid'"
        :class="['next', 'my-three-menu__button', { disabled: gridIndex === gridLayerCount - 1 }]"
        ref="next"
        @click="jumpNext()"
      >
        &lt;MyIcon :name="'icon-mono-right-fill'" svg>&lt;/MyIcon>
      &lt;/div>
    &lt;/div>
  &lt;/div>
&lt;/template>
&lt;script>
  /**
   * 3D菜单
   * @author 李国师 chester
   * @module $ui/components/my-three-menu
   */
  import {addResizeListener, removeResizeListener} from 'element-ui/lib/utils/resize-event'
import * as THREE from 'three'
import MyIcon from '../../my-icon/src/Icon'
import '$ui/icons/mono-left-fill.js'
import '$ui/icons/mono-right-fill.js'
import '$ui/icons/odbc.js'
import '$ui/icons/all-fill.js'
import '$ui/icons/network.js'
import '$ui/icons/copy-rect-fill.js'
import { TWEEN } from 'three/examples/jsm/libs/tween.module.min'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import {
  CSS3DObject,
  CSS3DRenderer
} from 'three/examples/jsm/renderers/CSS3DRenderer'
import { cloneDeep } from '$ui/utils/util'
const defaultOption = {
        camera: {
        //   deep: 2000
        },
        table: {
          // x: 0,
          // y: 0,
        //   column: 10
        },
        sphere: {
        //   radius: 600
        },
        helix: {
        //   y: 50, // 圆柱的y坐标偏移
        //   radius: 800, // 圆柱的半径
        //   dy: 10 // 圆柱的层高
        },
        grid: {
        //   row: 3,
        //   column: 3,
        //   deep: 0,
        //   layerSpace: 200,
        //   x: -100,
        //   y: 400
        }
      }
  /**
   * 插槽
   * @member slots
   * @property {string} default 默认插槽，定义其它内容
   * @property {string} item 卡片插槽，定义其它内容
   */
export default {
  name: 'MyThreeMenu',
  components: {
    MyIcon
  },
      /**
     * 属性参数
     * @member props
     * @property {Array} [list] 卡片列表
     * @property {string} [width] 画布宽
     * @property {string} [height] 画布高
     * @property {number} [itemWidth] 卡片宽
     * @property {number} [itemHeight] 卡片高
     * @property {number} [itemSpace] 卡片边距
     * @property {string} [defaultLayout] 默认布局
     * @property {boolean} [showTab] 显示菜单
     * @property {boolean} [play] 是否自动播放
     * @property {number} [playDuration] 播放等待时长(ms)
     * @property {number} [transformDuration] 变换时长(ms)
     * @property {object} [options] 布局配置
     * @property {object} [options.camera] 摄像机配置
     * @property {number} [options.camera.deep] 默认摄像相机深度
     * @property {number} [options.camera.minDistance] 最近摄像相机深度
     * @property {number} [options.camera.maxDistance] 最远摄像相机深度
     * @property {number} [options.camera.minZoom] 最小缩放
     * @property {number} [options.camera.maxZoom] 最大缩放
     * @property {number} [options.camera.minPolarAngle] 垂直最小旋转角度
     * @property {number} [options.camera.maxPolarAngle] 垂直最大旋转角度
     * @property {number} [options.camera.minAzimuthAngle] 水平最小旋转角度
     * @property {number} [options.camera.maxAzimuthAngle] 水平最大旋转角度
     * @property {boolean} [options.camera.enableZoom] 是否可缩放
     * @property {boolean} [options.camera.enableRotate] 是否可旋转
     * @property {boolean} [options.camera.enablePan] 是否可鼠标右键拖动
     * @property {object} [options.table] 表格布局配置
     * @property {number} [options.table.x] x偏移
     * @property {number} [options.table.y] y偏移
     * @property {number} [options.table.column] 列数
     * @property {object} [options.sphere] 圆球布局配置
     * @property {number} [options.sphere.radius] 圆球半径
     * @property {number} [options.sphere.x] 圆球x偏移
     * @property {number} [options.sphere.y] 圆球y偏移
     * @property {object} [options.helix] 圆柱布局配置
     * @property {number} [options.helix.x] 圆柱x偏移
     * @property {number} [options.helix.y] 圆柱y偏移
     * @property {number} [options.helix.radius] 圆柱半径
     * @property {number} [options.helix.dy] 圆柱卡片高度差
     * @property {object} [options.grid] 网格布局配置
     * @property {number} [options.grid.x] 网格x偏移
     * @property {number} [options.grid.y] 网格y偏移
     * @property {number} [options.grid.row] 网格行数
     * @property {number} [options.grid.column] 网格列数
     * @property {number} [options.grid.layerSpace] 网格层距
     **/
  props: {
    list: {
      type: Array,
      default() {
        return []
      }
    },
    width: {
        type: String,
        default: '100%'
    },  
    height: {
        type: String,
        default: '400px'
    },
    itemWidth: {
        type: Number,
        default: 200
    },
      itemHeight: {
          type: Number,
          default: 150
      },
      itemSpace: {
          type: Number,
          default: 5
      },
      defaultLayout: {
          type: String,
          default: 'table',
          validator: (val) => {
              return ['table', 'helix', 'sphere', 'grid'].includes(val)
          }
      },
      showTab: {
          type: Boolean,
          default: true
      },
      options: {
          type: Object,
          default() {
              return defaultOption
          }
      },
      play: Boolean,
      playDuration: {
          type: Number,
          default: 6000
      },
      transformDuration: {
          type: Number,
          default: 1000
      }
  },
  computed: {
    styles() {
        return {
        width: this.width,
        height: this.height
        }
    }
  },
  watch: {
      play(val) {
          if(val) {
              this.playCamera()
          } else if(!val &amp;&amp; this.playTimeout) {
              clearTimeout(this.playTimeout)
          }
      },
      options: {
          deep: true,
          handler(val) {
               this.layoutOption = Object.assign({}, defaultOption, this.options)
          }
      }
  },
  data() {
    return {
    // 组件内部变量
      screenWidth: 400,
      screenHeight: 100,
      objects: [],
      targets: { table: [], sphere: [], helix: [], grid: [] },
      camera: null,
      scene: null,
      renderer: null,
      controls: null,
      elements: [],
      column: 1,
      gridIndex: 0,
      gridLayerCount: 0,
      playTimeout: null,
      loopTimeout: null,
      playIndex: 0,
      currLayout: '',
      tweenGroup: [],
      layoutOption: {},
      angle: 0
    }
  },
  methods: {
    init() {
      this.layoutOption = Object.assign({}, defaultOption, this.options)
      this.camera = new THREE.PerspectiveCamera(
        40,
        this.screenWidth / this.screenHeight,
        1,
        10000
      )
      this.camera.position.z =
        this.layoutOption.camera.deep !== undefined
          ? this.layoutOption.camera.deep
          : (this.itemHeight + this.itemSpace) * this.column + 500

      this.scene = new THREE.Scene()
        const vector = new THREE.Vector3()
      // table
      this.initTable(vector)
      // sphere
      this.initSphere(vector)
      // helix
      this.initHelix(vector)
      // grid
       const gridColumn = Math.ceil(Math.pow(this.objects.length, 1 / 3))
      this.initGrid(vector, gridColumn)

      this.renderer = new CSS3DRenderer()
      this.renderer.setSize(this.screenWidth, this.screenHeight)
      this.$refs.container.appendChild(this.renderer.domElement)
     const defaultMaxDistance = 1500 * Math.floor(this.objects.length / (gridColumn * gridColumn)) +
        (this.itemHeight + this.itemSpace) * this.column * 1.5 +
        500
      this.setControl(defaultMaxDistance)
      this.transform(this.defaultLayout, this.transformDuration)
      window.addEventListener('resize', this.onWindowResize, false)
      this.$el.addEventListener('click', this.handleLoop, false)
      if(this.play) {
          this.playCamera()
      }
        addResizeListener(this.$el, this.setScreenSize)
       this.setScreenSize()
    },
    setControl(defaultMaxDistance) {
        this.controls = new OrbitControls(
        this.camera,
        this.renderer.domElement
      )
     
      const _cameraOption = cloneDeep(this.layoutOption.camera || {})
      if(_cameraOption.minPolarAngle !== undefined) {
        _cameraOption.minPolarAngle = _cameraOption.minPolarAngle * Math.PI / 180
      }
      if(_cameraOption.maxPolarAngle !== undefined) {
        _cameraOption.maxPolarAngle = _cameraOption.maxPolarAngle * Math.PI / 180
      }
      if(_cameraOption.minAzimuthAngle !== undefined) {
        _cameraOption.minAzimuthAngle = _cameraOption.minAzimuthAngle * Math.PI / 180
      }
      if(_cameraOption.maxAzimuthAngle !== undefined) {
        _cameraOption.maxAzimuthAngle = _cameraOption.maxAzimuthAngle * Math.PI / 180
      }
      delete _cameraOption.deep
      const cameraOption = Object.assign({}, {
        minDistance: 100,
        maxDistance: defaultMaxDistance,
        minZoom: 0,
        maxZoom: Infinity,
        minPolarAngle: 0,
        maxPolarAngle: Math.PI,
        minAzimuthAngle: -Infinity,
        maxAzimuthAngle: Infinity,
        enableZoom: true,
        enableRotate: true,
        enablePan: true
      }, _cameraOption)
      for(const name in cameraOption) {
        this.controls[name] = cameraOption[name]
      }
      this.controls.addEventListener('change', this.listRender)
    },
    initTable(vector) {
         const tableCol =
        this.layoutOption.table.column !== undefined
          ? this.layoutOption.table.column
          : this.column
      const tableRow = Math.ceil(this.elements.length / tableCol)
      const tableWidth = (this.itemWidth + this.itemSpace) * tableCol
      const tableHeight = (this.itemHeight + this.itemSpace) * tableRow
      const tableX =
        this.layoutOption.table.y !== undefined ? this.layoutOption.table.x : 0
      const tableY =
        this.layoutOption.table.y !== undefined ? this.layoutOption.table.y : 0
      for (let i = 0; i &lt; this.elements.length; i++) {
        const element = this.$el.querySelector(
          `.my-three-menu__item[data-index="${i}"]`
        )
        const objectCSS = new CSS3DObject(element)
        objectCSS.position.x = Math.random() * 4000 - 2000
        objectCSS.position.y = Math.random() * 4000 - 2000
        objectCSS.position.z = Math.random() * 4000 - 2000
        this.scene.add(objectCSS)
        this.objects.push(objectCSS)
        const object = new THREE.Object3D()
        const dx = Math.floor(i % tableCol)
        const dy = Math.floor(i / tableCol)
        object.position.x =
          dx * (this.itemWidth + this.itemSpace) -
          (tableWidth - this.itemWidth) / 2 +
          tableX
        object.position.y =
          -dy * (this.itemHeight + this.itemSpace) + tableHeight / 2 + tableY
        this.targets.table.push(object)
      }
    },
    initSphere(vector) {
         
      const sphereRadius =
        this.layoutOption.sphere.radius ||
        Math.sqrt(this.itemWidth * this.itemHeight * this.objects.length * 3 / (4 * Math.PI))
      for (let i = 0, l = this.objects.length; i &lt; l; i++) {
        const phi = Math.acos(-1 + (2 * i) / l)
        const theta = Math.sqrt(l * Math.PI) * phi
        const object = new THREE.Object3D()

        object.position.setFromSphericalCoords(sphereRadius, phi, theta)
        vector.copy(object.position).multiplyScalar(2)

        object.lookAt(vector)
        const x = object.position.x + (this.layoutOption.sphere.x || 0)
        const y = object.position.y + (this.layoutOption.sphere.y || 0)
        const z = object.position.z
        object.position.set(x, y, z)
        this.targets.sphere.push(object)
      }
    },
    initHelix(vector) {
         const helixRadius =
        this.layoutOption.helix.radius || (this.itemWidth + this.itemSpace) * 4
      const length = 2 * Math.PI * helixRadius
      const count = length / (this.itemWidth + this.itemSpace)
      const offsetY =
        (Math.ceil(this.objects.length / count) *
          (this.itemHeight + this.itemSpace)) /
        2
      for (let i = 0, l = this.objects.length; i &lt; l; i++) {
        let theta = i * 0.175 + Math.PI
        theta = (i * Math.PI * 2) / count + Math.PI
        const dy =
          this.layoutOption.helix.dy === undefined
            ? -((i * (this.itemHeight + this.itemSpace)) / count)
            : -i * this.layoutOption.helix.dy
        const y = dy + offsetY

        const object = new THREE.Object3D()

        object.position.setFromCylindricalCoords(helixRadius, theta, y)

        vector.x = object.position.x * 2
        vector.y = object.position.y
        vector.z = object.position.z * 2

        object.lookAt(vector)

        const tX = object.position.x + (this.layoutOption.helix.x || 0)
        const tY = object.position.y + (this.layoutOption.helix.y || 0)
        object.position.set(tX, tY, object.position.z)
        this.targets.helix.push(object)
      }

    },
    initGrid(vector, gridColumn) {
      const gridRow = this.layoutOption.grid.row || gridColumn
      const gridCol = this.layoutOption.grid.column || gridColumn
      this.gridLayerCount = Math.ceil(this.objects.length / (gridCol * gridRow))
      const gridOffsetXStatic =
        ((this.itemWidth + this.itemSpace) * (gridCol - 1)) / 2
      const gridOffsetYStatic =
        ((this.itemHeight + this.itemSpace) * (gridRow - 1)) / 2
      const gridOffsetX = -gridOffsetXStatic + (this.layoutOption.grid.x || 0)
      const gridOffsetY = gridOffsetYStatic + (this.layoutOption.grid.y || 0)
      const gridOffsetDeep =
        this.layoutOption.grid.deep !== undefined ? this.layoutOption.grid.deep : 800
      const layerSpace = this.layoutOption.grid.layerSpace || 800
      for (let i = 0; i &lt; this.objects.length; i++) {
        const object = new THREE.Object3D()
        object.position.x = (i % gridCol) * (this.itemWidth + this.itemSpace) + gridOffsetX
        object.position.y = -(Math.floor(i / gridCol) % gridRow) * (this.itemHeight + this.itemSpace) + gridOffsetY
        object.position.z =
          -(Math.floor(i / (gridCol * gridRow))) * layerSpace +
          gridOffsetDeep
        this.targets.grid.push(object)
      }
    },
    handleLoop() {
        if(this.playTimeout) {
            clearTimeout(this.playTimeout)
        }
        if(this.loopTimeout) {
            clearTimeout(this.loopTimeout)
        }
        if(this.play) {
            this.loopTimeout = setTimeout(() => {
                this.playCamera()
            }, 10000)
        }
    },
    playCamera() {
       this.playTimeout = setInterval(() => {
           this.playIndex++
           this.playIndex = this.playIndex % 4
           const target = ['table', 'sphere', 'helix', 'grid'][this.playIndex]
           this.transform(target, this.transformDuration)
       }, this.playDuration) 
    },
    transLayout(name) {
        this.transform(name, this.transformDuration)
    },
    jumpPrev() {
         if (this.gridIndex !== 0) {
            this.gridIndex--
          }
          this.jumpLayer()
    },
    jumpNext() {
        if (this.gridIndex &lt; this.gridLayerCount - 1) {
                    this.gridIndex++
          }
          this.jumpLayer()
    },
    jumpLayer() {
       const gridColumn = Math.ceil(Math.pow(this.objects.length, 1 / 3))
      const gridRow = this.layoutOption.grid.row || gridColumn
      const gridCol = this.layoutOption.grid.column || gridColumn
      this.gridLayerCount = Math.ceil(this.objects.length / (gridCol * gridRow))
      const gridOffsetXStatic =
        ((this.itemWidth + this.itemSpace) * (gridCol - 1)) / 2
      const gridOffsetYStatic =
        ((this.itemHeight + this.itemSpace) * (gridRow - 1)) / 2
      const gridOffsetX = -gridOffsetXStatic + (this.layoutOption.grid.x || 0)
      const gridOffsetY = gridOffsetYStatic + (this.layoutOption.grid.y || 0)
      const gridOffsetDeep =
        this.layoutOption.grid.deep !== undefined ? this.layoutOption.grid.deep : 800
      const layerSpace = this.layoutOption.grid.layerSpace || 800
      this.targets.grid = []
      for (let i = 0; i &lt; this.objects.length; i++) {
        const object = new THREE.Object3D()
        const layerIndex = Math.floor(i / (gridCol * gridRow))
       object.position.x = (i % gridCol) * (this.itemWidth + this.itemSpace) + gridOffsetX
        if (layerIndex &lt; this.gridIndex) {
          object.position.y = -10000
        } else {
          object.position.y =
            -(Math.floor(i / gridCol) % gridRow) *
              (this.itemHeight + this.itemSpace) +
            gridOffsetY
        }
        object.position.z =
          -(Math.floor(i / (gridCol * gridRow)) - this.gridIndex) *
            layerSpace +
          gridOffsetDeep
        this.targets.grid.push(object)
      }
      this.transform('grid', this.transformDuration)
    },
    transform(targetName, duration) {
        this.currLayout = targetName
        const targets = this.targets[targetName]
        this.removeAllTween()
      for (let i = 0; i &lt; this.objects.length; i++) {
        const object = this.objects[i]
        const target = targets[i]

        const t1 = new TWEEN.Tween(object.position)
          .to(
            {
              x: target.position.x,
              y: target.position.y,
              z: target.position.z
            },
            Math.random() * duration + duration
          )
          .easing(TWEEN.Easing.Exponential.InOut)
          .start()

        const t2 = new TWEEN.Tween(object.rotation)
          .to(
            {
              x: target.rotation.x,
              y: target.rotation.y,
              z: target.rotation.z
            },
            Math.random() * duration + duration
          )
          .easing(TWEEN.Easing.Exponential.InOut)
          .start()
          this.tweenGroup.push(t1, t2)
      }

      const t3 = new TWEEN.Tween(this)
        .to({}, duration * 2)
        .onUpdate(this.listRender)
        .start()
        this.tweenGroup.push(t3)
    },
    removeAllTween() {
        if(this.tweenGroup.length !== 0) {
            for(let i = 0; i &lt; this.tweenGroup.length; i++) {
              this.tweenGroup[i].stop()
            }
        }
        this.tweenGroup = []
    },
    onWindowResize() {
      this.camera.aspect = this.screenWidth / this.screenHeight
      this.camera.updateProjectionMatrix()
      this.renderer.setSize(this.screenWidth, this.screenHeight)
      this.listRender()
    },
    animate() {
        TWEEN.update()
        this.controls.update()
         this.renderer.render(this.scene, this.camera)
        requestAnimationFrame(this.animate)
    },
    listRender() {
        if(this.renderer) {
            this.renderer.render(this.scene, this.camera)
        }
    },
    setData() {
      const column = Math.ceil(Math.sqrt(this.list.length))
      this.column = column
      const elems = []
      for (let i = 0; i &lt; this.list.length; i++) {
        const item = {
          ...this.list[i]
        }
        elems.push(item)
      }
      this.elements = elems
    },
    setScreenSize() {
        const rect = this.$el.getBoundingClientRect()
        this.screenWidth = rect.width
        this.screenHeight = rect.height
        if(this.renderer) {
            this.renderer.setSize(this.screenWidth, this.screenHeight)
        }
    },
    reset() {
        this.objects = []
        this.targets = { table: [], sphere: [], helix: [], grid: [] }
        this.camera = null
        this.scene = null
        this.renderer = null
        this.elements = []
        if(this.playTimeout) {
            clearTimeout(this.playTimeout)
        }
        if(this.loopTimeout) {
            clearTimeout(this.loopTimeout)
        }
        this.removeAllTween()
         this.$el.removeEventListener('click', this.handleLoop, false)
        removeResizeListener(this.$el, this.setScreenSize)
    }
  },
  created() {
    this.setData()
  },
  mounted() {
    this.init()
    this.animate()
  },
  beforeDestroy() {
      this.reset()
  }
}
&lt;/script></code></pre>
        </article>
    </section>





    
</div>

<br class="clear">

<footer>
    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.6</a> on Fri Oct 08 2021 11:19:44 GMT+0800 (GMT+08:00) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>

<script>prettyPrint();</script>
<script src="scripts/polyfill.js"></script>
<script src="scripts/linenumber.js"></script>




<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?c4e5f73318b5cb0c389e3d9a05f831cc";
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(hm, s);
})();
</script>

</body>
</html>
